﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Krile.Kernel.WindowsEx;
using System.Drawing.Imaging;

namespace Twinkle.Dialogs
{
    public partial class ImageUploader : Form
    {
        public ImageUploader(string comment)
        {
            InitializeComponent();
            this.Comment = comment;
            UploadedUrl = null;
        }

        string Comment;

        public Point DisplayPadding = new Point();

        public string UploadedUrl { get; set; }

        public ImageUploader(Image image, string comment) : this(comment)
        {
            openImage = true;
            displaying = image;
        }

        bool openImage = false;
        Image displaying = null;
        bool whiting = false;
        Rectangle trimRect = new Rectangle(0, 0, 0, 0);

        private void ImageUploader_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (openImage)
            {
                if (
                    MessageBoxEx.ShowDialog(null, Lang.Msg.ImageUploadCancel_Context, Lang.Msg.ImageUploadCancel,
                    Lang.Msg.ImageUploadCancel_Title, MessageBoxEx.MessageBoxExButtons.OKCancel, MessageBoxEx.MessageBoxExIcon.Warning) == MessageBoxEx.DialogResultEx.Cancel)
                {
                    e.Cancel = true;
                }
                else
                {
                    DisposeDisplayingImage();
                }
            }
        }

        private void zoomTrackBar_ValueChanged(object sender, EventArgs e)
        {
            if (displaying != null)
            {
                var vsm = displaying.Height * zoomTrackBar.Value / 100 - imageView.Height;
                if (vsm > 0)
                {
                    vScrollbar.Enabled = true;
                    vScrollbar.Maximum = vsm;
                    if (vScrollbar.Value > vScrollbar.Maximum)
                        vScrollbar.Value = vScrollbar.Maximum;
                }
                else
                {
                    vScrollbar.Enabled = false;
                }

                var hsm = displaying.Width * zoomTrackBar.Value / 100 - imageView.Width;
                if (hsm > 0)
                {
                    hScrollbar.Enabled = true;
                    hScrollbar.Maximum = hsm;
                    if (hScrollbar.Value > hScrollbar.Maximum)
                        hScrollbar.Value = hScrollbar.Maximum;
                }
                else
                {
                    hScrollbar.Enabled = false;
                }
                this.Refresh();
            }
        }

        private void hScrollbar_Scroll(object sender, ScrollEventArgs e)
        {
            hScrollbar_ValueChanged(sender, e);
        }

        private void hScrollbar_ValueChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void vScrollbar_Scroll(object sender, ScrollEventArgs e)
        {
            vScrollbar_ValueChanged(sender, e);
        }

        private void vScrollbar_ValueChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void openImageFromFile_Click(object sender, EventArgs e)
        {
            using (var ofd = new OpenFileDialog())
            {
                ofd.Filter = "Images|*.png;*.gif;*.bmp;*.jpg;*.gif";
                ofd.Title = "Open image file";
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        DisposeDisplayingImage();
                        displaying = Image.FromFile(ofd.FileName);
                        this.Refresh();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Image open error:" + ex.Message);
                    }
                }
                AutoResize();
            }
        }

        private void openImageFromDesktop_Click(object sender, EventArgs e)
        {
            Rectangle rect = Screen.PrimaryScreen.Bounds;
            Bitmap bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(rect.X, rect.Y, 0, 0, rect.Size, CopyPixelOperation.SourceCopy);
            }

            DisposeDisplayingImage();
            displaying = bmp;
            this.Refresh();
        }

        private void openImageFromClipboard_Click(object sender, EventArgs e)
        {
            try
            {
                var img = Clipboard.GetImage();
                if (img != null)
                {
                    DisposeDisplayingImage();
                    displaying = img;
                    this.Refresh();
                }
                else
                    MessageBoxEx.ShowDialog(this, Lang.Msg.ClipboardError_Context, Lang.Msg.ClipboardError_NotImage, Lang.Msg.ClipboardError_Title, MessageBoxEx.MessageBoxExButtons.Close, MessageBoxEx.MessageBoxExIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBoxEx.ShowDialog(this, Lang.Msg.ClipboardError_Context, ex.Message, Lang.Msg.ClipboardError_Title, MessageBoxEx.MessageBoxExButtons.Close, MessageBoxEx.MessageBoxExIcon.Error);
            }
        }

        private void DisposeDisplayingImage()
        {
            if (displaying != null)
            {
                var img = displaying;
                displaying = null;
                img.Dispose();
                img = null;
            }
        }

        private void fitImage_Click(object sender, EventArgs e)
        {
            AutoResize();
        }

        private void AutoResize()
        {
            if (displaying == null) return;
            int hv = imageView.Width * 100 / displaying.Width;
            int vv = imageView.Height * 100 /  displaying.Height;
            if (hv > 100 && vv > 100)
            {
                hv = 100;
                vv = 100;
            }
            zoomTrackBar.Value = hv > vv ? vv : hv;
        }

        private void trimmingImage_Click(object sender, EventArgs e)
        {
            trimmingImage.Enabled = false;
            var img = new Bitmap(trimRect.Size.Width, trimRect.Size.Height);
            using (var g = Graphics.FromImage(img))
            {
                g.DrawImage(displaying, new Rectangle(0, 0, trimRect.Width, trimRect.Height), trimRect, GraphicsUnit.Pixel);
            }
            DisposeDisplayingImage();
            displaying = img;
            AutoResize();
            this.Refresh();
        }

        private void imageView_MouseDown(object sender, MouseEventArgs e)
        {
            if (hScrollbar.Enabled)
                trimRect.X = (e.X + hScrollbar.Value) * 100 / zoomTrackBar.Value;
            else
                trimRect.X = (e.X - DisplayPadding.X) * 100 / zoomTrackBar.Value;

            if (vScrollbar.Enabled)
                trimRect.Y = (e.Y + vScrollbar.Value) * 100 / zoomTrackBar.Value;
            else
                trimRect.Y = (e.Y - DisplayPadding.Y) * 100 / zoomTrackBar.Value;

            if (trimRect.X < 0)
                trimRect.X = 0;
            if (trimRect.Y < 0)
                trimRect.Y = 0;
            whiting = true;
            this.Refresh();
        }

        private void imageView_MouseMove(object sender, MouseEventArgs e)
        {
            if (whiting)
            {
                var nw = (e.X + hScrollbar.Value - DisplayPadding.X) * 100 / zoomTrackBar.Value - trimRect.X;
                if (!hScrollbar.Enabled)
                    nw = (e.X - DisplayPadding.X) * 100 / zoomTrackBar.Value - trimRect.X; 
                if (nw > 0)
                {
                    trimRect.Width = nw;
                }
                else
                {
                    trimRect.Width = -nw;
                    trimRect.X += nw;
                }
                var nh = (e.Y + vScrollbar.Value - DisplayPadding.Y) * 100 / zoomTrackBar.Value - trimRect.Y;
                if (!vScrollbar.Enabled)
                    nh = (e.Y - DisplayPadding.Y) * 100 / zoomTrackBar.Value - trimRect.Y; 
                if (nh > 0)
                {
                    trimRect.Height = nh;
                }
                else
                {
                    trimRect.Height = -nh;
                    trimRect.Y += nh;
                }
                if (trimRect.Right > displaying.Width)
                    trimRect.Width = displaying.Width - trimRect.X;
                if(trimRect.Bottom > displaying.Height)
                    trimRect.Height = displaying.Height - trimRect.Y;
                this.Refresh();
            }
        }

        private void imageView_MouseUp(object sender, MouseEventArgs e)
        {
            if (whiting)
            {
                imageView_MouseMove(sender, e);
                imageView.Refresh();
                trimmingImage.Enabled = true;
                whiting = false;
            }
        }

        private void imageView_Paint(object sender, PaintEventArgs e)
        {
            if (displaying == null) return;
            var sourceRect = new Rectangle(0, 0, displaying.Width, displaying.Height);
            var destRect = new Rectangle(0,0, imageView.Width, imageView.Height);
            if (hScrollbar.Enabled)
            {
                // 描画領域の方が大きい
                sourceRect.X += hScrollbar.Value;
                sourceRect.Width = imageView.Width * 100 / zoomTrackBar.Value;
            }
            else
            {
                // 画像の方が大きい
                destRect.Width = displaying.Width * zoomTrackBar.Value / 100;
                destRect.X = (imageView.Width - destRect.Width) / 2;
            }
            if (vScrollbar.Enabled)
            {
                // 描画領域の方が大きい
                sourceRect.Y += vScrollbar.Value;
                sourceRect.Height = imageView.Height * 100 / zoomTrackBar.Value;
            }
            else
            {
                // 画像の方が大きい
                destRect.Height = displaying.Height * zoomTrackBar.Value / 100;
                destRect.Y = (imageView.Height - destRect.Height) / 2;
            }
            DisplayPadding = destRect.Location;
            e.Graphics.DrawImage(displaying, destRect, sourceRect, GraphicsUnit.Pixel);
            Rectangle trimDisplayRect = new Rectangle(
                (trimRect.X) * zoomTrackBar.Value / 100 + DisplayPadding.X,
                (trimRect.Y) * zoomTrackBar.Value / 100 + DisplayPadding.Y,
                trimRect.Width * zoomTrackBar.Value / 100,
                trimRect.Height * zoomTrackBar.Value / 100);

            if (whiting || trimmingImage.Enabled)
            {
                using (var b = new SolidBrush(Color.FromArgb(120, Color.White)))
                {
                    if (trimDisplayRect.Y > 0)
                    {
                        var topRect = new Rectangle(0, 0, imageView.Width, trimDisplayRect.Y);
                        e.Graphics.FillRectangle(b, topRect);
                    }
                    if (trimDisplayRect.X > 0)
                    {
                        var leftRect = new Rectangle(0, trimDisplayRect.Y, trimDisplayRect.X, imageView.Height - trimDisplayRect.Y);
                        e.Graphics.FillRectangle(b, leftRect);
                    }
                    if (trimDisplayRect.Right < imageView.Width)
                    {
                        var rightRect = new Rectangle(trimDisplayRect.Right, trimDisplayRect.Y, imageView.Width - trimDisplayRect.Right, imageView.Height - trimDisplayRect.Y);
                        e.Graphics.FillRectangle(b, rightRect);
                    }
                    if (trimDisplayRect.Bottom < imageView.Height)
                    {
                        var bottomRect = new Rectangle(trimDisplayRect.X, trimDisplayRect.Bottom, trimDisplayRect.Width, imageView.Height - trimDisplayRect.Bottom);
                        e.Graphics.FillRectangle(b, bottomRect);
                    }
                    e.Graphics.DrawRectangle(Pens.Red, trimDisplayRect);
                }
            }
        }

        private void uploadImage_Click(object sender, EventArgs e)
        {
            if(displaying != null)
            {
                if (MessageBoxEx.ShowDialog(this,
                        Lang.Msg.UploadImage_Context,
                        Lang.Msg.UploadImage,
                        Lang.Msg.TreatAsDm_Title, MessageBoxEx.MessageBoxExButtons.YesNo, MessageBoxEx.MessageBoxExIcon.Question) == MessageBoxEx.DialogResultEx.No)
                    return;
                try
                {
                    var path = System.IO.Path.GetTempFileName();
                    System.IO.File.Delete(path);
                    try
                    {
                        displaying.Save(path);
                        using (var uploading = new UploadingView())
                        {
                            uploading.Show(this);
                            var inv = new Action(() =>
                            {
                                if (Kernel.Config.External.ImageEmbeddingService.UseImageEmbedding)
                                {
                                    switch (Kernel.Config.External.ImageEmbeddingService.EmbeddingService)
                                    {
                                        case Twinkle.Data.Config.ExternalConfig.ImageEmbeddingServiceDescriptor.ImageEmbeddingServices.TwitPic:
                                            var tp = new External.TwitPicUpload();
                                            var tret = tp.UploadImage(path, Kernel.Config.External.ImageEmbeddingService.ID, Kernel.Config.External.ImageEmbeddingService.PW, Comment);
                                            this.UploadedUrl = tret;
                                            break;
                                        case Twinkle.Data.Config.ExternalConfig.ImageEmbeddingServiceDescriptor.ImageEmbeddingServices.Posterous:
                                            var pp = new External.PosterousUpload();
                                            var pret = pp.UploadImage(path, Kernel.Config.External.ImageEmbeddingService.ID, Kernel.Config.External.ImageEmbeddingService.PW, Comment);
                                            this.UploadedUrl = pret;
                                            break;
                                        case Twinkle.Data.Config.ExternalConfig.ImageEmbeddingServiceDescriptor.ImageEmbeddingServices.Gyazo:
                                            var gp = new External.GyazoUpload();
                                            var gret = gp.UploadImage(path);
                                            this.UploadedUrl = gret;
                                            break;
                                    }
                                }
                            });
                            var ctx = inv.BeginInvoke((iar) => inv.EndInvoke(iar), null);
                            while (!ctx.IsCompleted)
                            {
                                Application.DoEvents();
                                System.Threading.Thread.Sleep(10);
                            }
                            uploading.CloseDialog();
                        }
                    }
                    finally
                    {
                        System.IO.File.Delete(path);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Image save error:" + ex.Message);
                }
                DisposeDisplayingImage();
                openImage = false;
                this.Close();
            }
        }

        private void imageView_Resize(object sender, EventArgs e)
        {
            imageView.Refresh();
        }

        private void ImageUploader_Load(object sender, EventArgs e)
        {
            AutoResize();
        }

    }
}
